//Verilog HDL for "Lib6710Project", "VGA" "verilog"


module VGA (CLK, RST, MEM, ADDR, READ, OUT, VSYNC_OUTB, HSYNC_OUTB);
	input CLK;
	input RST;
	input [15:0] MEM;
	output [17:0] ADDR;
	output READ;
	output [7:0] OUT;
	output VSYNC_OUTB;
	output HSYNC_OUTB;
	wire CLK;
	wire RST;
	wire [15:0] MEM;
	reg [17:0] ADDR;
	reg READ;
	reg [7:0] OUT;
	reg VSYNC_OUTB;
	reg HSYNC_OUTB;

	reg [18:0] VCOUNT;
	reg [9:0] HCOUNT;
	reg [8:0] HPIXCOUNT;
	reg [8:0] VPIXCOUNT;
	reg VDRAWING;
	reg HDRAWING;

	// Timings for a true 512x384x8bit resolution using a 16MHz clock.
	// 16MHz clock is 266,666 62.5ns clocks
	//
	//parameter VSYNC_PULSE_WIDTH = 19'd968;
	//parameter VBACK_PORCH_WIDTH = 19'd20866;
	//parameter VACTIVE_WIDTH = 19'd237696;
	//parameter VFRONT_PORCH_WIDTH = 19'd7259;
	//parameter HSYNC_PULSE_WIDTH = 10'd61;
	//parameter HBACK_PORCH_WIDTH = 10'd31;
	//parameter HACTIVE_WIDTH = 10'd512;
	//parameter HFRONT_PORCH_WIDTH = 10'd15;
	
	// Timings for a 640x480 resolution with 512x384x8bit usable using a 25MHz clock.
	// 25MHz clock is 416,666 40ns clocks
	//
	parameter VSYNC_PULSE_WIDTH = 19'd1588;
	parameter VBACK_PORCH_WIDTH = 19'd61932;
	parameter VACTIVE_WIDTH = 19'd304896;
	parameter VFRONT_PORCH_WIDTH = 19'd47640;
	parameter HSYNC_PULSE_WIDTH = 10'd96;
	parameter HBACK_PORCH_WIDTH = 10'd96;
	parameter HACTIVE_WIDTH = 10'd512;
	parameter HFRONT_PORCH_WIDTH = 10'd90;
	
	parameter VSYNC_PULSE_START = 19'd0;
	parameter VBACK_PORCH_START = VSYNC_PULSE_WIDTH;
	parameter VACTIVE_START = VSYNC_PULSE_WIDTH + VBACK_PORCH_WIDTH;
	parameter VFRONT_PORCH_START = VSYNC_PULSE_WIDTH + VBACK_PORCH_WIDTH + VACTIVE_WIDTH;
	parameter VCYCLE_END = VSYNC_PULSE_WIDTH + VBACK_PORCH_WIDTH + VACTIVE_WIDTH + VFRONT_PORCH_WIDTH - 1;
	
	parameter HSYNC_PULSE_START = 10'd0;
	parameter HBACK_PORCH_START = HSYNC_PULSE_WIDTH;
	parameter HACTIVE_START = HSYNC_PULSE_WIDTH + HBACK_PORCH_WIDTH;
	parameter HFRONT_PORCH_START = HSYNC_PULSE_WIDTH + HBACK_PORCH_WIDTH + HACTIVE_WIDTH;
	parameter HCYCLE_END = HSYNC_PULSE_WIDTH + HBACK_PORCH_WIDTH + HACTIVE_WIDTH + HFRONT_PORCH_WIDTH - 1;

always @ (posedge CLK)
begin
	if (RST == 1'b1 || VCOUNT == VCYCLE_END)	begin
		VCOUNT <= 19'b0;
		HCOUNT <= 10'b0;
		HPIXCOUNT <= 9'b0;
		VPIXCOUNT <= 9'b0;
		VDRAWING <= 1'b0;
		HDRAWING <= 1'b0;
		ADDR <= 19'b0;
		READ <= 1'b0;
		OUT <= 8'b0;
		VSYNC_OUTB <= 1'b1;
		HSYNC_OUTB <= 1'b1;
	end
	else begin
		//Always increment counts
		VCOUNT <= VCOUNT + 1;
		HCOUNT <= HCOUNT + 1;
		
		//Vertical Counter State Machine
		if (VCOUNT == VSYNC_PULSE_START) begin
			VSYNC_OUTB <= 1'b0;
		end
		else if (VCOUNT == VBACK_PORCH_START) begin
			VSYNC_OUTB <= 1'b1;
		end
		else if (VCOUNT == VACTIVE_START) begin
			VDRAWING <= 1'b1;
		end
		else if (VCOUNT == VFRONT_PORCH_START) begin
			VDRAWING <= 1'b0;
		end
		
		//Horizontal Counter State Machine
		if (HCOUNT == HSYNC_PULSE_START) begin
			HSYNC_OUTB <= 1'b0;
		end
		else if (HCOUNT == HBACK_PORCH_START) begin
			HSYNC_OUTB <= 1'b1;
		end
		else if (HCOUNT == HACTIVE_START) begin
			HDRAWING <= 1'b1;
		end
		else if (HCOUNT == HFRONT_PORCH_START) begin
			HDRAWING <= 1'b0;
			if (VDRAWING == 1'b1) begin
				//HPIXCOUNT <= 9'b1; //Already at 0, so initialize counter to 1
				HPIXCOUNT <= 9'b0;
				VPIXCOUNT <= VPIXCOUNT + 1;
			end
		end
		else if (HCOUNT == HCYCLE_END) begin
			HCOUNT <= 10'b0;
		end
		
		//Output selector
		if (VDRAWING == 1'b1 && HDRAWING == 1'b1)	begin
			HPIXCOUNT <= HPIXCOUNT + 1;
			
			//Even pixel - Read 16-bit word from SRAM and output lower byte of read data
			if (HCOUNT[0] == 1'b0) begin
				READ <= 1'b1;
				//Arbitrary base address via an addition of BASE_ADDR[17:0]
				//ADDR <= BASE_ADDR + {1'b0,VPIXCOUNT[8:0],HPIXCOUNT[8:1]};
				//Video memory is addressed from 0x10000 -- 0x27FFF
				//TODO: Signal that switches memory offset to 0x28000 -- 0x3FFFF 
				ADDR <= {VPIXCOUNT[8],~VPIXCOUNT[8],VPIXCOUNT[7:0],HPIXCOUNT[8:1]};
				OUT <= MEM[7:0];
			end
			//Odd pixel - Deassert READ signal and output upper byte of read data
			else begin
				READ <= 1'b0;
				OUT <= MEM[15:8];
			end
		end
		else begin
			READ <= 1'b0;
			ADDR <= 18'b0;
			OUT <= 8'b0;
		end
		
	end
end

endmodule
